﻿namespace Microsoft.Xna.Framework
{
    /// <summary>
    /// 	Defines a rectangle.
    /// </summary>
    public static class RectangleExtensions
    {
        #region Static Operations

        #region Intersect

        /// <summary>
        /// 	Creates a Rectangle defining the area where one rectangle overlaps with another rectangle.
        /// </summary>
        /// <param name="value1"> The first Rectangle to compare. </param>
        /// <param name="value2"> The second Rectangle to compare. </param>
        public static Rectangle Intersect(Rectangle value1, Rectangle value2)
        {
            Rectangle rectangle;
            var value1Right = value1.X + value1.Width;
            var value2Right = value2.X + value2.Width;
            var value1Bottom = value1.Y + value1.Height;
            var value2Bottom = value2.Y + value2.Height;
            var mostRightX = (value1.X > value2.X) ? value1.X : value2.X;
            var mostBottomY = (value1.Y > value2.Y) ? value1.Y : value2.Y;
            var mostLeftRight = (value1Right < value2Right) ? value1Right : value2Right;
            var mostTopBottom = (value1Bottom < value2Bottom) ? value1Bottom : value2Bottom;
            if ((mostLeftRight > mostRightX) && (mostTopBottom > mostBottomY))
            {
                rectangle.X = mostRightX;
                rectangle.Y = mostBottomY;
                rectangle.Width = mostLeftRight - mostRightX;
                rectangle.Height = mostTopBottom - mostBottomY;
                return rectangle;
            }
            rectangle.X = 0;
            rectangle.Y = 0;
            rectangle.Width = 0;
            rectangle.Height = 0;
            return rectangle;
        }

        /// <summary>
        /// 	Creates a Rectangle defining the area where one rectangle overlaps with another rectangle.
        /// </summary>
        /// <param name="value1"> The first Rectangle to compare. </param>
        /// <param name="value2"> The second Rectangle to compare. </param>
        /// <param name="result"> [OutAttribute] The area where the two first parameters overlap. </param>
        public static void Intersect(ref Rectangle value1, ref Rectangle value2, out Rectangle result)
        {
            var value1Right = value1.X + value1.Width;
            var value2Right = value2.X + value2.Width;
            var value1Bottom = value1.Y + value1.Height;
            var value2Bottom = value2.Y + value2.Height;
            var mostRightX = (value1.X > value2.X) ? value1.X : value2.X;
            var mostBottomY = (value1.Y > value2.Y) ? value1.Y : value2.Y;
            var mostLeftRight = (value1Right < value2Right) ? value1Right : value2Right;
            var mostTopBottom = (value1Bottom < value2Bottom) ? value1Bottom : value2Bottom;
            if ((mostLeftRight > mostRightX) && (mostTopBottom > mostBottomY))
            {
                result.X = mostRightX;
                result.Y = mostBottomY;
                result.Width = mostLeftRight - mostRightX;
                result.Height = mostTopBottom - mostBottomY;
            }
            else
            {
                result.X = 0;
                result.Y = 0;
                result.Width = 0;
                result.Height = 0;
            }
        }

        #endregion

        #region Union

        /// <summary>
        /// 	Creates a new Rectangle that exactly contains two other rectangles.
        /// </summary>
        /// <param name="value1"> The first Rectangle to contain. </param>
        /// <param name="value2"> The second Rectangle to contain. </param>
        public static Rectangle Union(Rectangle value1, Rectangle value2)
        {
            Rectangle rectangle;
            var value1Right = value1.X + value1.Width;
            var value2Right = value2.X + value2.Width;
            var value1Bottom = value1.Y + value1.Height;
            var value2Bottom = value2.Y + value2.Height;
            var mostLeftX = (value1.X < value2.X) ? value1.X : value2.X;
            var mostTopY = (value1.Y < value2.Y) ? value1.Y : value2.Y;
            var mostRightRight = (value1Right > value2Right) ? value1Right : value2Right;
            var mostBottomBottom = (value1Bottom > value2Bottom) ? value1Bottom : value2Bottom;
            rectangle.X = mostLeftX;
            rectangle.Y = mostTopY;
            rectangle.Width = mostRightRight - mostLeftX;
            rectangle.Height = mostBottomBottom - mostTopY;
            return rectangle;
        }

        /// <summary>
        /// 	Creates a new Rectangle that exactly contains two other rectangles.
        /// </summary>
        /// <param name="value1"> The first Rectangle to contain. </param>
        /// <param name="value2"> The second Rectangle to contain. </param>
        /// <param name="result"> [OutAttribute] The Rectangle that must be the union of the first two rectangles. </param>
        public static void Union(ref Rectangle value1, ref Rectangle value2, out Rectangle result)
        {
            var value1Right = value1.X + value1.Width;
            var value2Right = value2.X + value2.Width;
            var value1Bottom = value1.Y + value1.Height;
            var value2Bottom = value2.Y + value2.Height;
            var mostLeftX = (value1.X < value2.X) ? value1.X : value2.X;
            var mostTopY = (value1.Y < value2.Y) ? value1.Y : value2.Y;
            var mostRightRight = (value1Right > value2Right) ? value1Right : value2Right;
            var mostBottomBottom = (value1Bottom > value2Bottom) ? value1Bottom : value2Bottom;
            result.X = mostLeftX;
            result.Y = mostTopY;
            result.Width = mostRightRight - mostLeftX;
            result.Height = mostBottomBottom - mostTopY;
        }

        #endregion

        #endregion

        #region Offset

        /// <summary>
        /// 	Changes the position of the Rectangle.
        /// </summary>
        /// <param name="rectangle"> The source rectangle. </param>
        /// <param name="amount"> The values to adjust the position of the Rectangle by. </param>
        public static void Offset(this Rectangle rectangle, Point amount)
        {
            rectangle.X += amount.X;
            rectangle.Y += amount.Y;
        }

        /// <summary>
        /// 	Changes the position of the Rectangle.
        /// </summary>
        /// <param name="rectangle"> The source rectangle. </param>
        /// <param name="offsetX"> Change in the x-position. </param>
        /// <param name="offsetY"> Change in the y-position. </param>
        public static void Offset(this Rectangle rectangle, int offsetX, int offsetY)
        {
            rectangle.X += offsetX;
            rectangle.Y += offsetY;
        }

        #endregion

        #region Inflate

        /// <summary>
        /// 	Pushes the edges of the Rectangle out by the horizontal and vertical values specified.
        /// </summary>
        /// <param name="rectangle"> The source rectangle. </param>
        /// <param name="horizontalAmount"> Value to push the sides out by. </param>
        /// <param name="verticalAmount"> Value to push the top and bottom out by. </param>
        public static void Inflate(this Rectangle rectangle, int horizontalAmount, int verticalAmount)
        {
            rectangle.X -= horizontalAmount;
            rectangle.Y -= verticalAmount;
            rectangle.Width += horizontalAmount * 2;
            rectangle.Height += verticalAmount * 2;
        }

        #endregion

        #region Contains

        /// <summary>
        /// 	Determines whether this Rectangle contains a specified point represented by its x- and y-coordinates.
        /// </summary>
        /// <param name="rectangle"> The source rectangle. </param>
        /// <param name="x"> The x-coordinate of the specified point. </param>
        /// <param name="y"> The y-coordinate of the specified point. </param>
        public static bool Contains(this Rectangle rectangle, int x, int y)
        {
            return (rectangle.X <= x) && (x < (rectangle.X + rectangle.Width)) && (rectangle.Y <= y) && (y < (rectangle.Y + rectangle.Height));
        }

        /// <summary>
        /// 	Determines whether this Rectangle contains a specified Point.
        /// </summary>
        /// <param name="rectangle"> The source rectangle. </param>
        /// <param name="value"> The Point to evaluate. </param>
        public static bool Contains(this Rectangle rectangle, Point value)
        {
            return (rectangle.X <= value.X) && (value.X < (rectangle.X + rectangle.Width)) && (rectangle.Y <= value.Y) && (value.Y < (rectangle.Y + rectangle.Height));
        }

        /// <summary>
        /// 	Determines whether this Rectangle contains a specified Point.
        /// </summary>
        /// <param name="rectangle"> The source rectangle. </param>
        /// <param name="value"> The Point to evaluate. </param>
        /// <param name="result"> [OutAttribute] true if the specified Point is contained within this Rectangle; false otherwise. </param>
        public static void Contains(this Rectangle rectangle, ref Point value, out bool result)
        {
            result = (rectangle.X <= value.X) && (value.X < (rectangle.X + rectangle.Width)) && (rectangle.Y <= value.Y) && (value.Y < (rectangle.Y + rectangle.Height));
        }

        /// <summary>
        /// 	Determines whether this Rectangle entirely contains a specified Rectangle.
        /// </summary>
        /// <param name="rectangle"> The source rectangle. </param>
        /// <param name="value"> The Rectangle to evaluate. </param>
        public static bool Contains(this Rectangle rectangle, Rectangle value)
        {
            return (rectangle.X <= value.X) && ((value.X + value.Width) <= (rectangle.X + rectangle.Width)) && (rectangle.Y <= value.Y) && ((value.Y + value.Height) <= (rectangle.Y + rectangle.Height));
        }

        /// <summary>
        /// 	Determines whether this Rectangle entirely contains a specified Rectangle.
        /// </summary>
        /// <param name="rectangle"> The source rectangle. </param>
        /// <param name="value"> The Rectangle to evaluate. </param>
        /// <param name="result"> [OutAttribute] On exit, is true if this Rectangle entirely contains the specified Rectangle, or false if not. </param>
        public static void Contains(this Rectangle rectangle, ref Rectangle value, out bool result)
        {
            result = (rectangle.X <= value.X) && ((value.X + value.Width) <= (rectangle.X + rectangle.Width)) && (rectangle.Y <= value.Y) && ((value.Y + value.Height) <= (rectangle.Y + rectangle.Height));
        }

        #endregion

        #region Intersects

        /// <summary>
        /// 	Determines whether a specified Rectangle intersects with this Rectangle.
        /// </summary>
        /// <param name="rectangle"> The source rectangle. </param>
        /// <param name="value"> The Rectangle to evaluate. </param>
        public static bool Intersects(this Rectangle rectangle, Rectangle value)
        {
            return (value.X < (rectangle.X + rectangle.Width)) && (rectangle.X < (value.X + value.Width)) && (value.Y < (rectangle.Y + rectangle.Height)) && (rectangle.Y < (value.Y + value.Height));
        }

        /// <summary>
        /// 	Determines whether a specified Rectangle intersects with this Rectangle.
        /// </summary>
        /// <param name="rectangle"> The source rectangle. </param>
        /// <param name="value"> The Rectangle to evaluate </param>
        /// <param name="result"> [OutAttribute] true if the specified Rectangle intersects with this one; false otherwise. </param>
        public static void Intersects(this Rectangle rectangle, ref Rectangle value, out bool result)
        {
            result = (value.X < (rectangle.X + rectangle.Width)) && (rectangle.X < (value.X + value.Width)) && (value.Y < (rectangle.Y + rectangle.Height)) && (rectangle.Y < (value.Y + value.Height));
        }

        #endregion
    }
}